class Stars {

    constructor(opts) {
        this.options = opts;
        this.projectName = opts.projectName || '';
        let pathName = window.location.pathname.substring(1);
        let webName = pathName === '' ? '' : pathName.substring(0, pathName.indexOf('/'));
        this.contentPath = window.location.protocol + '//' + window.location.host + (webName === this.projectName ? '' : ('/' + webName));
        this.translateMap = {};
        this.translateLoaded = false;
        this.lang = 'zh';
        this.splitWords = '#@#';
        this.menu = [];
        this.page = {};
        this.pageHolder = {};
        this.pageIndex = 0;
        debugger;
        this.loadScript(this.contentPath + '/webjars/starsjs/lib/jquery.min.js', () => {
            debugger;
            $.getScript(this.contentPath + '/webjars/starsjs/lib/noty.min.js', () => this.init());
        });
        //$.when(
        //    $.getScript(this.contentPath + '/webjars/starsjs/lib/noty.min.js'),
        //    $.Deferred((deferred) => $(deferred.resolve))
        //).done(() => this.init());
    }

    init() {
        this.loadWebFont();
        this.options.login && this.addLoginModule(this.options.login);
    }

    addLoginModule(opts) {
        $.getScript(this.contentPath + '/webjars/starsjs/stars-login.js', () => this.loginStars = new LoginStars(this, opts));
    }

    loadWebFont() {
        $.getScript(this.contentPath + '/webjars/starsjs/lib/webfontloader.js', () => {
            WebFont.load({
                google: {"families": ["Montserrat:400,500,600,700", "Noto+Sans:400,700"]},
                active: function () {
                    sessionStorage.fonts = true;
                }
            });
        });
    }

    loadTranslateMap(url, func) {
        if (this.translateLoaded === true) {
            func && func();
            return;
        }
        if (url && url != '') {
            let index = url.indexOf(',');
            if (index == -1) {
                $.getJSON(this.contentPath + url, (data) => {
                    this.translateMap[url.substring(url.indexOf('_') + 1, url.indexOf('.'))] = data;
                    this.translateLoaded = true;
                    func && func();
                });
            } else if (index == 0) {
                this.loadTranslateMap(url.substr(1), func);
            } else {
                let currUrl = url.substr(0, index);
                $.getJSON(this.contentPath + currUrl, (data) => {
                    this.translateMap[currUrl.substring(currUrl.indexOf('_') + 1, currUrl.indexOf('.'))] = data;
                    this.loadTranslateMap(url.substr(index + 1), func);
                });
            }
        }
    }

    loadMenu(url, func) {
        $.getJSON(this.contentPath + url, (data) => {
            this.menu = data;
            func && func();
        });
    }

    getParentMenuItem(name) {
        return this.getMenuChildItem(this.menu, name, true);
    }

    getMenuChildItem(items, name, isParentItem, nameArray) {
        for (let i in items) {
            if (items.hasOwnProperty(i)) {
                if (items[i]['name'] === name) {
                    return items[i];
                }
                let childs = items[i]['childs'];
                if (childs != null) {
                    let menuItem = this.getMenuChildItem(childs, name, isParentItem, nameArray);
                    if (menuItem != null) {
                        nameArray && nameArray.push(menuItem.name);
                        return isParentItem ? items[i] : menuItem;
                    }
                }
            }
        }
        return null;
    }

    getMenuItem(parentMenuItem, name) {
        if (parentMenuItem['name'] === name) {
            return parentMenuItem;
        }
        let childs = parentMenuItem['childs'];
        if (childs != null) {
            let menuItem = this.getMenuChildItem(childs, name, false);
            if (menuItem != null) {
                return menuItem;
            }
        }
        return parentMenuItem;
    }

    getMenuNameArray(parentMenuItem, name) {
        let nameArray = [];
        if (parentMenuItem['name'] === name) {
            nameArray.push(name);
        } else {
            let childs = parentMenuItem['childs'];
            if (childs != null) {
                let menuItem = this.getMenuChildItem(childs, name, true, nameArray);
                if (menuItem != null) {
                    nameArray.push(menuItem.name);
                }
                nameArray.push(parentMenuItem.name);
            } else {
                nameArray.push(name);
            }
        }
        return nameArray;
    }

    refreshDataTables() {
        this.eachSearchPages(function (searchPage) {
            searchPage.refreshDataTable();
        });
    }

    eachSearchPages(fun) {
        let searchPages = this.getPageContext('searchPages') || [], length = searchPages.length;
        for (let i = 0; i < length; i++) {
            fun(searchPages[i]);
        }
    }

    translate(node) {
        let translateNodes = node.hasClass('translate') ? node : node.find('.translate');
        $.each(translateNodes, function (i, translateNode) {
            let $translateNode = $(translateNode);
            if ($translateNode.attr('translateFor')) {
                if ($translateNode.attr('translateTo')) {
                    $translateNode.attr($translateNode.attr('translateTo'), this.getTranslateValue($translateNode));
                } else {
                    $translateNode.text(this.getTranslateValue($translateNode));
                }
            }
            if ($translateNode.hasClass('lang')) {
                $translateNode.removeClass('en zh').addClass(lang);
            }
        });
        return node;
    }

    getTranslateValue($translateNode) {
        let translateFor = $translateNode.attr('translateFor') || '';
        let translateValue = this.getTranslateValueByFor(translateFor);
        if (translateValue === undefined || translateValue == '') {
            return '';
        }
        $translateNode.attr('translateValue') && (translateValue = translateValue[$translateNode.attr('translateValue')]);
        let translateReplace = $translateNode.attr('translateReplace');
        if (translateReplace && translateReplace !== '' && translateReplace !== 'undefined') {
            while (translateValue.includes('{}') && translateReplace != '') {
                let commaIndex = translateReplace.indexOf(';');
                let replaceTarget;
                if (commaIndex > 0) {
                    replaceTarget = translateReplace.substring(0, commaIndex);
                    translateReplace = translateReplace.substring(commaIndex + 1);
                } else {
                    replaceTarget = translateReplace;
                    translateReplace = '';
                }
                let replaceValue;
                let cdataStartIndex = replaceTarget.indexOf('cdata(');
                if (cdataStartIndex != -1) {
                    replaceValue = replaceTarget.substring(cdataStartIndex + 6, replaceTarget.indexOf(')'));
                } else {
                    replaceValue = this.getTranslateValueByFor(replaceTarget);
                }
                translateValue = translateValue.replace('{}', replaceValue);
            }
        }
        return translateValue;
    }

    changeTranslateValue(node, value) {
        let translateNodes = node.hasClass('translate') ? node : node.find('.translate');
        $.each(translateNodes, function (i, translateNode) {
            translate($(translateNode).attr('translateValue', value));
        });
    }

    cdata(str) {
        return 'cdata(' + str + ")";
    }

    getTranslateReplace(array) {
        if (array === undefined || array === null) {
            return "";
        }
        if (!(array instanceof Array)) {
            return array;
        }
        let str = "";
        for (let i in array) {
            if (array.hasOwnProperty(i)) {
                str += array[i] + ";";
            }
        }
        if (str !== "") {
            return str.substr(0, str.length - 1);
        }
        return str;
    }

    getTranslateFor($translateNode) {
        let translateFor = $translateNode.attr('translateFor') || '';
        let translateValue = $translateNode.attr('translateValue') || '';
        if (translateFor == '' && translateValue == '') {
            return '';
        } else if (translateFor == '' && translateValue != '') {
            return translateValue;
        } else if (translateFor != '' && translateValue == '') {
            return translateFor;
        }
        return translateFor + '.' + translateValue;
    }

    getTranslateValueByFor(translateFor) {
        if (translateFor == '') {
            return '';
        }
        let pointIndex = translateFor.indexOf('.');
        let translateValue = this.translateMap[lang];
        while (pointIndex > -1) {
            translateValue = translateValue[translateFor.substring(0, pointIndex)];
            translateFor = translateFor.substring(pointIndex + 1);
            pointIndex = translateFor.indexOf('.');
        }
        return translateValue[translateFor];
    }

    setLang(_lang) {
        lang = _lang;
    }

    getLang() {
        return lang;
    }

    changeLang(langSwitchBtn1, langSwitchBtn2, lang1, lang2) {
        langSwitchBtn1.addClass('switch-loading');
        langSwitchBtn2.addClass('switch-loading');
        lang = langSwitchBtn1.hasClass('switch-checked') ? lang2 : lang1;
        this.axiosPost({
            url: "/dbschedule/setting/changeLang/" + lang,
            success: function () {
                if (lang == lang2) {
                    langSwitchBtn1.removeClass('switch-checked');
                    langSwitchBtn2.addClass('switch-checked');
                } else {
                    langSwitchBtn1.addClass('switch-checked');
                    langSwitchBtn2.removeClass('switch-checked');
                }
                this.translate($('body'));
                this.refreshDataTables();
                langSwitchBtn1.removeClass('switch-loading');
                langSwitchBtn2.removeClass('switch-loading');
            }
        });
    }

    showPopover(node, options) {
        let id = options.id || 'default';
        let popoverTimeoutId = node.data('popoverTimeoutId_' + id);
        if (popoverTimeoutId != undefined && popoverTimeoutId != '') {
            clearTimeout(popoverTimeoutId);
            node.data('popoverTimeoutId_' + id, '');
        }
        let popover;
        let popoverId = node.data('popoverId_' + id);
        if (popoverId && popoverId != '') {
            popover = $('#' + popoverId);
        } else {
            popover = this.createPopover(options).data('node', node).data('firstShow', true);
            popoverId = popover.data('popoverId');
            node.data('popoverId_' + id, popoverId);
            let popoverIdMap = node.data('popoverIdMap');
            if (popoverIdMap == undefined) {
                popoverIdMap = {};
                node.data('popoverIdMap', popoverIdMap);
            }
            let popoverIdArray = popoverIdMap[id];
            if (popoverIdArray == undefined) {
                popoverIdArray = [];
                popoverIdMap[id] = popoverIdArray;
            } else if (popoverIdArray.length > 0) {
                for (let i in popoverIdArray) {
                    if (popoverIdArray.hasOwnProperty(i)) {
                        if (popoverIdArray[i] && popoverIdArray[i] != '') {
                            this.hidePopover($('#' + popoverIdArray[i]), true);
                        }
                    }
                }
            }
            popoverIdArray.pushWhenNotExist(popoverId);
        }
        this.setPopoverData(popover, options);
        popover.css('transform', 'translate3d(-2000px, -2000px, 0px)').show().data('show', true);
        this.adjustPopoverPosition(popover, true);
        let sepLayerId = popover.data('sepLayerId');
        if (sepLayerId && sepLayerId != '') {
            let seplayer = $('#' + sepLayerId);
            seplayer.addClass('z-index-9998').off('click').on('click', () => this.hidePopover(popover));
            popover.addClass('z-index-9999');
            node.addClass('z-index-9999');
            options.zIndex && node.css('z-index', 9999 + options.zIndex) && seplayer.css('z-index', 9998 + options.zIndex);
            let fixedTop = $('.fixed-top');
            if (fixedTop && fixedTop.length > 0) {
                fixedTop.each(function () {
                    let $this = $(this);
                    let fixedTopCover = $this.find('.cover');
                    if (fixedTopCover == undefined || fixedTopCover.length == 0) {
                        fixedTopCover = $('<div class="cover"></div>');
                        $this.prepend(fixedTopCover.addClass('z-index-9999'));
                    }
                    fixedTopCover.off('click').on('click', () => this.hidePopover(popover)).show();
                });
            }
        } else {
            $('#content').on('click.' + popoverId, (event) => {
                if (event.target === node[0]) {
                    return;
                }
                this.hidePopover(popover);
                $('#content').off('click.' + popoverId)
            });
        }
        options.zIndex && popover.css('z-index', 9999 + options.zIndex);
        return popover;
    }

    createPopover(options) {
        let popoverId = generateID('popover');
        let bodyStyle = options.bodyStyle || '';
        let bodyContent = options.bodyContent || '';
        let popover = $('<div id="' + popoverId + '" class="popover" style="position:absolute;will-change:transform;"></div>');
        let popoverBody = $('<div class="popover-body" style="' + bodyStyle + '"></div>');
        let body = $('body').append(popover.append($('<div class="arrow"></div>')).append(popoverBody.html(bodyContent)));
        options.niceScroll && popoverBody.niceScroll({
            cursorcolor: "rgba(52, 40, 104, 0.2)",
            cursorborder: "rgba(52, 40, 104, 0.2)"
        });
        if (options.scrollLock === true) {
            let sepLayerId = generateID('sepLayer');
            let sepLayer = $('<div class="separation-layer" id="' + sepLayerId + '"></div>');
            body.append(sepLayer);
            popover.data('sepLayerId', sepLayerId).data('scrollLock', options.scrollLock);
        }
        options.topFun && popover.data('topFun', options.topFun);
        options.bottomFun && popover.data('bottomFun', options.bottomFun);
        options.rightFun && popover.data('rightFun', options.rightFun);
        options.leftFun && popover.data('leftFun', options.leftFun);
        options.preHideFun && popover.data('preHideFun', options.preHideFun);
        options.hideFun && popover.data('hideFun', options.hideFun);
        popover.data('popoverId', popoverId);
        return popover;
    }

    setPopoverData(popover, options) {
        if (options.allowBodyChange === true && options.bodyContent !== undefined && popover.data('bodyContent') !== options.bodyContent) {
            getPopoverBody(popover).html(options.bodyContent);
        }
        return popover.data('id', options.id || 'default').data('direction', options.direction || 'top').data('bodyStyle', options.bodyStyle || '').data('bodyContent', options.bodyContent || '')
            .data('popoverLeft', options.left).data('popoverTop', options.top).data('leftOffset', options.leftOffset).data('topOffset', options.topOffset)
            .data('animate', options.animate || 'no').data('animateTime', options.animateTime || 500).data('hideRemove', options.hideRemove);
    }

    getPopoverId(node, id) {
        return node.data('popoverId_' + (id || 'default'));
    }

    getPopoverBody(popover) {
        return popover.find('.popover-body');
    }

    adjustAllPopoverPositionByNode(node) {
        let popoverIdMap = node.data('popoverIdMap');
        if (popoverIdMap != undefined) {
            for (let key in popoverIdMap) {
                if (popoverIdMap.hasOwnProperty(key)) {
                    this.adjustPopoverPositionByNode(node, key);
                }
            }
        }
    }

    adjustPopoverPositionByNode(node, id) {
        let popoverIdMap = node.data('popoverIdMap');
        if (popoverIdMap != undefined) {
            id = id || 'default';
            let popoverIdArray = popoverIdMap[id];
            if (popoverIdArray && popoverIdArray.length > 0) {
                let oPopoverId = node.data('popoverId_' + id);
                for (let i in popoverIdArray) {
                    if (popoverIdArray.hasOwnProperty(i)) {
                        let popoverId = popoverIdArray[i];
                        if (popoverId && popoverId != '') {
                            if (popoverId === oPopoverId) {
                                this.adjustPopoverPosition($('#' + popoverId));
                            } else {
                                this.hidePopover($('#' + popoverId), true);
                            }
                        }
                    }
                }
            }
        }
    }

    adjustPosition() {
        var that = this;
        $('.popover').each(function () {
            let $this = $(this);
            if ($this.data('show') === true) {
                that.adjustPopoverPosition($this);
                let popoverTop = $this.offset().top;
                popoverTop != 0 && (popoverTop + 2 < $("#content").offset().top || popoverTop + $this[0].offsetHeight - 2 > $(window).height()) && $this.css('transform', 'translate3d(-2000px, -2000px, 0px)');
            }
        });
    }

    adjustPopoverPosition(popover, init, _direction, turn) {
        if (popover == undefined || popover == null || popover.data('show') !== true) {
            return;
        }
        let direction = _direction || popover.data('direction'), node = popover.data('node'), left, top;
        popover.removeClass('bs-popover-top bs-popover-bottom bs-popover-right bs-popover-left').addClass('bs-popover-' + direction).attr('x-placement', direction);
        let popoverOffsetHeight = popover.data('popoverOffsetHeight') ? popover.data('popoverOffsetHeight') : popover[0].offsetHeight;
        let popoverOffsetWidth = popover.data('popoverOffsetWidth') ? popover.data('popoverOffsetWidth') : popover[0].offsetWidth;
        let popoverClientHeight = popover.data('popoverClientHeight') ? popover.data('popoverClientHeight') : popover[0].clientHeight;
        let popoverClientWidth = popover.data('popoverClientWidth') ? popover.data('popoverClientWidth') : popover[0].clientWidth;
        let directionFun;
        let rem = parseInt($('html').css('font-size').replace('px', ''));
        if (direction === 'top') {
            popover.find('.arrow').css('left', (popoverClientWidth - 14) / 2);
            left = popover.data('popoverLeft') ? this.calcPx(popover.data('popoverLeft'), rem) : (node.offset().left - ((popoverOffsetWidth - node[0].offsetWidth) / 2));
            top = popover.data('popoverTop') ? this.calcPx(popover.data('popoverTop'), rem) : (node.offset().top - popoverOffsetHeight - 7);
            directionFun = popover.data('topFun');
        } else if (direction === 'bottom') {
            popover.find('.arrow').css('left', (popoverClientWidth - 14) / 2);
            left = popover.data('popoverLeft') ? this.calcPx(popover.data('popoverLeft'), rem) : (node.offset().left - ((popoverOffsetWidth - node[0].offsetWidth) / 2));
            top = popover.data('popoverTop') ? this.calcPx(popover.data('popoverTop'), rem) : (node.offset().top + node[0].offsetHeight);
            directionFun = popover.data('bottomFun');
        } else if (direction === 'right') {
            popover.find('.arrow').css('top', (popoverClientHeight - 14) / 2);
            left = popover.data('popoverLeft') ? this.calcPx(popover.data('popoverLeft'), rem) : (node.offset().left + node[0].offsetWidth);
            top = popover.data('popoverTop') ? this.calcPx(popover.data('popoverTop'), rem) : (node.offset().top - ((popoverOffsetHeight - node[0].offsetHeight) / 2));
            directionFun = popover.data('rightFun');
        } else {
            popover.find('.arrow').css('top', (popoverClientHeight - 14) / 2);
            left = popover.data('popoverLeft') ? this.calcPx(popover.data('popoverLeft'), rem) : (node.offset().left - popoverOffsetWidth - 7);
            top = popover.data('popoverTop') ? this.calcPx(popover.data('popoverTop'), rem) : (node.offset().top - ((popoverOffsetHeight - node[0].offsetHeight) / 2));
            directionFun = popover.data('leftFun');
        }
        let animateTime = popover.data('animateTime');
        if (popover.data('firstShow') === true) {
            directionFun && setTimeout(function () {
                directionFun(popover)
            }, parseInt((animateTime || 500) / 2));
            popover.data('firstShow', false);
        } else {
            directionFun && directionFun(popover);
        }
        popover.data('popoverOffsetWidth', popoverOffsetWidth).data('popoverOffsetHeight', popoverOffsetHeight).data('popoverClientHeight', popoverClientHeight).data('popoverClientWidth', popoverClientWidth);
        popover.data('leftOffset') && (left = left + this.calcPx(popover.data('leftOffset'), rem));
        popover.data('topOffset') && (top = top + this.calcPx(popover.data('topOffset'), rem));
        if (direction === 'top' && top < $('#content').offset().top && turn !== true) {
            this.adjustPopoverPosition(popover, init, 'bottom', true);
            return;
        } else if (direction === 'bottom' && top + popoverOffsetHeight > $(window).height() && turn !== true) {
            this.adjustPopoverPosition(popover, init, 'top', true);
            return;
        }
        init && popover.hide();
        popover.css('transform', 'translate3d(' + this.getEvenNumber(left) + 'px, ' + this.getEvenNumber(top) + 'px, 0px)');
        if (init) {
            let animate = popover.data('animate');
            if (animate == 'slide') {
                popover.slideDown(animateTime);
            } else if (animate == 'fade') {
                popover.fadeIn(animateTime);
            } else {
                popover.show();
            }
        }
    }

    calcPx(value, rem) {
        if (value.includes('rem')) {
            return parseFloat(value.replace('rem', '')) * rem;
        } else if (value.includes('px')) {
            return parseFloat(value.replace('px', ''));
        }
        return value;
    }

    getPopover(node, id) {
        let popoverId = node.data('popoverId_' + (id || 'default'));
        if (popoverId && popoverId != '') {
            return $('#' + popoverId);
        }
    }

    hidePopoverByNode(node, id) {
        let popoverIdMap = node.data('popoverIdMap');
        if (popoverIdMap != undefined) {
            id = id || 'default';
            let popoverIdArray = popoverIdMap[id];
            if (popoverIdArray && popoverIdArray.length > 0) {
                let oPopoverId = node.data('popoverId_' + id);
                for (let i in popoverIdArray) {
                    if (popoverIdArray.hasOwnProperty(i)) {
                        let popoverId = popoverIdArray[i];
                        if (popoverId && popoverId != '') {
                            if (popoverId === oPopoverId) {
                                this.hidePopover($('#' + popoverId));
                            } else {
                                this.hidePopover($('#' + popoverId), true);
                            }
                        }
                    }
                }
            }
        }
    }

    hideAllPopoverByNode(node) {
        let popoverIdMap = node.data('popoverIdMap');
        if (popoverIdMap != undefined) {
            for (let key in popoverIdMap) {
                if (popoverIdMap.hasOwnProperty(key)) {
                    this.hidePopoverByNode(node, key);
                }
            }
        }
    }

    hidePopover(popover, immediately, hideRemove) {
        if (popover == undefined || popover == null || popover.data('show') !== true) {
            return;
        }
        let preHideFun = popover.data('preHideFun');
        preHideFun && preHideFun();
        let animate = popover.data('animate');
        let animateTime = popover.data('animateTime');
        if (animate == 'slide') {
            popover.slideUp(animateTime);
        } else if (animate == 'fade') {
            popover.fadeOut(animateTime);
        } else {
            popover.hide();
        }
        popover.data('show', false);
        let id = popover.data('id');
        let node = popover.data('node');
        hideRemove = hideRemove || popover.data('hideRemove');
        if (hideRemove === undefined || hideRemove == true) {
            immediately === true ? removePopover(node, popover, id) : node.data('popoverTimeoutId_' + id, setTimeout(function () {
                removePopover(node, popover, id)
            }, 5000));
        }
        let sepLayerId = popover.data('sepLayerId');
        if (sepLayerId && sepLayerId != '') {
            $('#' + sepLayerId).removeClass('z-index-9998').off('click');
            popover.removeClass('z-index-9999');
            node.removeClass('z-index-9999');
            let fixedTopCover = $('.fixed-top .cover');
            fixedTopCover && fixedTopCover.off('click').hide();
        }
        let hideFun = popover.data('hideFun');
        hideFun && hideFun();
        function removePopover(node, popover, id) {
            let popoverIdMap = node.data('popoverId_' + id, '').data('popoverTimeoutId_' + id, '').data('popoverIdMap');
            if (popoverIdMap != undefined) {
                let popoverIdArray = popoverIdMap[id];
                popoverIdArray && popoverIdArray.remove(popover.data('popoverId'));
            }
            let sepLayerId = popover.data('sepLayerId');
            if (sepLayerId && sepLayerId != '') {
                let sepLayer = $('#' + sepLayerId);
                sepLayer && sepLayer.detach();
            }
            popover && popover.detach();
        }
    }

    createSlider(options) {
        let sliderId = generateID('slider');
        let container = $('<div id="' + sliderId + '"></div>');
        let sliderTooltip = $('<div class="slider-tooltip"></div>');
        let sliderValue = $('<span class="slider-value"></span>');
        let slider = $('<div class="slider"></div>');
        let sliderRail = $('<div class="slider-rail"></div>');
        let sliderTrack = $('<div class="slider-track"></div>');
        let sliderStep = $('<div class="slider-step"></div>');
        let sliderHandle = $('<div class="slider-handle"></div>');
        let sliderMark = $('<div class="slider-mark"></div>');
        container.append(sliderTooltip.append(sliderValue)).append(slider.append(sliderRail).append(sliderTrack).append(sliderStep).append(sliderHandle).append(sliderMark));
        options.background && sliderRail.css('background', options.background) && sliderTrack.css('background', options.background);
        let minValue = options.min || 0;
        let maxValue = options.max || 100;
        let defaultValue = options.defaultValue || minValue;
        minValue >= maxValue && (minValue = maxValue - 1);
        defaultValue < minValue && (defaultValue = minValue);
        defaultValue > maxValue && (defaultValue = maxValue);
        let gap = 100 / (maxValue - minValue);
        let left = defaultValue == minValue ? 0 : (defaultValue == maxValue ? 100 : (defaultValue - minValue) * gap);
        sliderTrack.css('left', '0%').css('width', left + "%");
        if (options.popover) {
            sliderTooltip.hide();
        } else {
            sliderValue.text(defaultValue + (options.unit || '')).css('left', left + '%');
        }
        let popover, popoverContent = $('<span style="width:1.425rem;text-align:center"></span>'), popoverTimeoutId = -1, popoverOptions = {
            direction: 'top',
            bodyStyle: 'width:2.14rem;height:2.14rem;font-size:1rem;padding:0.35rem 0.35rem',
            bodyContent: popoverContent,
            animate: 'fade',
            animateTime: 300
        };
        sliderHandle.css('left', left + '%').on('mousedown', () => {
            popoverTimeoutId != -1 && clearTimeout(popoverTimeoutId);
            sliderHandle.addClass('selected');
            options.popover && (popover = this.showPopover(sliderHandle, popoverOptions)) && popoverContent.text((container.data('sliderValue') || defaultValue) + (options.unit || ''));
            $(document).off('mousemove').off('mouseup').on('mousemove', (event) => {
                move(event.clientX);
                options.popover && this.adjustPopoverPosition(popover);
            }).on('mouseup', () => {
                $(document).off('mousemove').off('mouseup');
                sliderHandle.removeClass('selected');
                (options.popover && this.hidePopoverByNode(sliderHandle));
            });
        });
        slider.on('mousedown', (event) => {
            if (event.target === sliderHandle[0]) {
                return;
            }
            move(event.clientX);
            if (options.popover) {
                popover = this.showPopover(sliderHandle, popoverOptions);
                popoverContent.text((container.data('sliderValue') || defaultValue) + (options.unit || ''));
                popoverTimeoutId != -1 && clearTimeout(popoverTimeoutId);
                popoverTimeoutId = setTimeout(() => this.hidePopover(popover), 1500);
            }
        });
        function move(eventLeft) {
            let sliderRailWidth = sliderRail[0].clientWidth;
            let gapWidth = sliderRailWidth / (maxValue - minValue) / 2;
            let offsetLeft = eventLeft - sliderRail.offset().left;
            let value, left;
            if (offsetLeft < gapWidth) {
                value = minValue;
                left = 0;
            } else if (offsetLeft >= sliderRailWidth - gapWidth) {
                value = maxValue;
                left = 100;
            } else {
                value = Math.round(offsetLeft / gapWidth / 2) + minValue;
                left = (value - minValue) * gap;
            }
            sliderHandle.css('left', left + '%');
            sliderTrack.css('width', left + '%');
            let valueWithUnit = value + (options.unit || '');
            if (options.popover) {
                popoverContent.text(valueWithUnit);
            } else {
                sliderValue.text(valueWithUnit).css('left', left + '%');
            }
            container.data('sliderValue', value);
        }

        return container.data('sliderId', sliderId);
    }

    getSliderValue(slider) {
        return slider.data('sliderValue');
    }

    bindDoubleBoxPopover(node, options) {
        let createDoublebox = ($this, popover, doubleSelect, options) => {
            $this.data('doubleBox') && $this.data('doubleBox').destroy();
            $this.data('doubleBox', doubleSelect.doublebox({
                nonSelectedListLabel: '<span class="translate" translateFor="doubleBox.label.nonSelectedList.' + (options.name || 'default') + '"></span>',
                selectedListLabel: '<span class="translate" translateFor="doubleBox.label.selectedList.' + (options.name || 'default') + '"></span>',
                preserveSelectionOnMove: 'moved',
                moveOnSelect: false,
                doubleMove: true,
                selectorMinimalHeight: 200,
                loading: '<span class="translate" translateFor="doubleBox.loading" style="margin:.5rem 0 0 .7rem"></span>',
                infoText: '{0}/{1} <span class="translate" translateFor="doubleBox.item"></span>',
                infoTextFiltered: '{0}/{1}/{2} <span class="translate" translateFor="doubleBox.item"></span>',
                reload: true,
                reloadFun: () => loadData($this, doubleSelect, options)
            }));
            this.getPopoverBody(popover).find('.settingUp-btns').append($('<button class="btn btn-default" id="double-box-ok"><span class="translate" translateFor="btn.ok"></span></button>').on('click', () => this.hidePopover(popover)));
        };
        let loadData = ($this, doubleSelect, options) => {
            if (options.loadUrl) {
                this.axiosPost({
                    url: options.loadUrl,
                    success: function (data) {
                        refreshDoublebox($this, doubleSelect, data.list || []);
                    }
                });
            } else {
                refreshDoublebox($this, doubleSelect, options.data || []);
            }
        };
        let refreshDoublebox = function ($this, doubleSelect, tdata) {
            let sValueData = $this.data('allData') || [];
            let tValueData = [];
            if (tdata.length > 0) {
                for (let i in tdata) {
                    if (tdata.hasOwnProperty(i)) {
                        let item = tdata[i];
                        let itemValue = item.value;
                        tValueData.push(itemValue);
                        if ($.inArray(itemValue, sValueData) == -1) {
                            doubleSelect.append($("<option id='doublebox_option_" + itemValue + "' value='" + itemValue + "'>" + item.text + "</option>"));
                        }
                    }
                }
            }
            if (sValueData.length > 0) {
                for (let j in sValueData) {
                    if (sValueData.hasOwnProperty(j)) {
                        let sItemValue = sValueData[j];
                        if ($.inArray(sItemValue, tValueData) == -1) {
                            doubleSelect.find('#doublebox_option_' + sItemValue).remove();
                        }
                    }
                }
            }
            $this.data('allData', tValueData);
            $this.data('doubleBox').refresh();
        };
        let getColor = function (index) {
            let colorArray = ['#dc3545', '#ffc107', '#28a745', '#007bff', '#6610f2'];
            return colorArray[index % colorArray.length];
        };
        node.on(options.trigger || 'focus', () => {
            options.fun && options.fun.beforeShow && options.fun.beforeShow();
            let id = 'doubleBox';
            let firstLoad = this.getPopoverId(node, id) == undefined;
            let newPopover = firstLoad || this.getPopoverId(node, id) == '';
            let doubleSelectName = 'doubleSelect';
            let doubleSelect = $('<select multiple="multiple" name="' + doubleSelectName + '"></select>');
            node.addClass('focus');
            let popover = this.showPopover(node, {
                id: id,
                direction: options.direction || 'top',
                animate: 'slide',
                animateTime: 300,
                bodyStyle: 'height:21.425rem;width:42.85rem;font-weight:600;padding:0.715rem 2rem',
                bodyContent: doubleSelect,
                hideRemove: false,
                scrollLock: false,
                topFun: function (popover) {
                    popover.find('#double-box-ok').addClass('double-box-ok-bottom').removeClass('double-box-ok-top');
                },
                bottomFun: function (popover) {
                    popover.find('#double-box-ok').addClass('double-box-ok-top').removeClass('double-box-ok-bottom');
                },
                preHideFun: () => {
                    let text = doubleSelect.getSelectedOptionsText(doubleSelectName);
                    let value = doubleSelect.getSelectedOptionsValue(doubleSelectName);
                    node.removeClass('focus').val(text).data('value', value);
                    this.listenDoubleboxWithCloseBtn(node);
                    let textArray = text.split(',');
                    if (textArray.length > 1) {
                        let bodyContent = '';
                        let index = 0;
                        for (let i in textArray) {
                            if (textArray.hasOwnProperty(i)) {
                                bodyContent += '<span style="color:' + getColor(index) + '">' + textArray[i] + '</span>';
                                if (textArray.length != ++index) {
                                    bodyContent += '<span style="color:green">,&nbsp;</span>';
                                }
                            }
                        }
                        this.createTitle(node, {
                            id: 'title',
                            bodyStyle: 'min-height:2.85rem;max-width:42.85rem',
                            bodyContent: bodyContent
                        });
                    } else {
                        this.removeTitle(node);
                    }
                    options.fun && options.fun.callBack && options.fun.callBack(text, value);
                }
            });
            newPopover && createDoublebox(node, popover, doubleSelect, options);
            firstLoad && loadData(node, doubleSelect, options);
            this.translate(popover);
        });
    }

    createTitle(node, _options) {
        this.removeTitle(node);
        node.hover(() => {
            let options = $.extend({}, _options);
            for (let i in options) {
                if (options.hasOwnProperty(i)) {
                    if (options[i] && typeof options[i] === 'function') {
                        options[i] = options[i]();
                    }
                }
            }
            options['allowBodyChange'] = true;
            this.showPopover(node, options)
        }, () => this.hidePopoverByNode(node, _options.id));
    }

    removeTitle(node, _options) {
        node.unbind('mouseenter').unbind('mouseleave');
        this.hidePopoverByNode(node, _options && _options.id);
    }

    generateID(id) {
        id = (id ? id + '_' : '') + '0xxxxxxx-1xxx-2xxx-3xxx-yxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                let r = Math.random() * 16 | 0;
                let v = c === 'x' ? r : r & 0x3 | 0x8;
                return v.toString(16);
            });
        return id;
    }

    beautifySelect(node) {
        let selectNodes = node.is("select") ? node : node.find('select');
        $.each(selectNodes, function (i, selectNode) {
            //let selectContainer = $('<span class="beautify-select"></span>');
            //selectNode = $(selectNode).after(selectContainer);
            //selectContainer.append(selectNode.detach()).append($('<button type="button" class="btn btn-default"><i class="la la-chevron-down"></i></button>').on('click', function () {
            //    selectNode.trigger("mousedown")
            //}));
            $(selectNode).addClass('beautify-select')
        });

    }

    createTitleWithIconBtn(node) {
        let tem;
        if (node.hasClass('iconBtn')) {
            tem = node;
        } else {
            tem = node.find('.iconBtn');
        }
        var that = this;
        tem.each(function () {
            let $this = $(this);
            that.createTitle($this, {
                bodyContent: () => {
                    return $this.attr('popoverTitle')
                }
            });
        });
    }

    getSearchValue(filterValue) {
        let filterArray = [];
        if (filterValue != '') {
            filterArray = filterValue.split(this.splitWords);
        }
        let searchValue = '';
        for (let p in filterArray) {
            if (filterArray.hasOwnProperty(p)) {
                if (searchValue == '') {
                    searchValue = this.getTranslateValueByFor(filterArray[p]);
                } else {
                    searchValue = searchValue + '|' + this.getTranslateValueByFor(filterArray[p]);
                }
            }
        }
        return searchValue;
    }

    pushPageContext(key, value) {
        let pageContext = this.page['pageContext'];
        if (pageContext == undefined || pageContext == null) {
            pageContext = {};
            this.page['pageContext'] = pageContext;
        }
        pageContext[key] = value;
    }

    getPageContext(key) {
        let pageContext = this.page['pageContext'];
        if (pageContext != undefined && pageContext != null) {
            let value = pageContext[key];
            if (value != undefined) {
                return value;
            }
        }
        return null;
    }

    getPageData() {
        return this.getPageContext('data');
    }

    pushModalContext(modalId, key, value) {
        if (modalId == undefined || modalId == null) {
            alert('未配置modalId!');
            return;
        }
        let pageModalId = 'modal-' + modalId;
        let modalContext = this.page[pageModalId];
        if (modalContext == undefined || modalContext == null) {
            modalContext = {};
            this.page[pageModalId] = modalContext;
        }
        modalContext[key] = value;
    }

    getModalContext(modalId, key) {
        if (modalId != undefined && modalId != null) {
            let modalContext = this.page['modal-' + modalId];
            if (modalContext != undefined && modalContext != null) {
                let value = modalContext[key];
                if (value != undefined) {
                    return value;
                }
            }
        }
        return null;
    }

    getModalData(modalId) {
        return this.getModalContext(modalId, 'data');
    }

    setPageTimeout(code, delay) {
        let pageTimeoutId = this.getPageContext('pageTimeoutId');
        if (pageTimeoutId === null || pageTimeoutId === undefined) {
            this.pushPageContext('pageTimeoutCode', code);
            this.pushPageContext('pageTimeoutDelay', delay);
            this.pushPageContext('pageTimeoutId', setTimeout(() => {
                this.clearPageTimeoutParam();
                typeof code === "function" ? code() : eval(code);
                this.pushPageContext('pageTimeoutId', null);
            }, delay));
        }
    }

    clearPageTimeout(fun, keepTimeoutParam) {
        let pageTimeoutId = this.getPageContext('pageTimeoutId');
        if (pageTimeoutId !== undefined && pageTimeoutId !== null) {
            clearTimeout(pageTimeoutId);
            this.pushPageContext('pageTimeoutId', null);
            fun && fun();
        }
        keepTimeoutParam !== true && this.clearPageTimeoutParam();
    }

    clearPageTimeoutParam() {
        this.pushPageContext('pageTimeoutCode', null);
        this.pushPageContext('pageTimeoutDelay', null);
    }

    setModalTimeout(modalId, code, delay) {
        let modalTimeoutId = this.getModalContext(modalId, 'modalTimeoutId');
        if (modalTimeoutId === null || modalTimeoutId === undefined) {
            this.pushModalContext(modalId, 'modalTimeoutCode', code);
            this.pushModalContext(modalId, 'modalTimeoutDelay', delay);
            this.pushModalContext(modalId, 'modalTimeoutId', setTimeout(() => {
                this.clearModalTimeoutParam(modalId);
                typeof code === "function" ? code() : eval(code);
                this.pushModalContext(modalId, 'modalTimeoutId', null);
            }, delay));
        }
    }

    clearModalTimeout(modalId, fun, keepTimeoutParam) {
        let modalTimeoutId = getModalContext(modalId, 'modalTimeoutId');
        if (modalTimeoutId !== undefined && modalTimeoutId !== null) {
            clearTimeout(modalTimeoutId);
            this.pushModalContext(modalId, 'modalTimeoutId', null);
            fun && fun();
        }
        keepTimeoutParam !== true && this.clearModalTimeoutParam(modalId);
    }

    clearModalTimeoutParam(modalId) {
        this.pushModalContext(modalId, 'modalTimeoutCode', null);
        this.pushModalContext(modalId, 'modalTimeoutDelay', null);
    }

    dataTableNiceScrolls() {
        eachSearchPages(function (searchPage) {
            searchPage.dataTableNiceScroll();
        });
    }

    textEllipsis(node, isRemove) {
        let textEllipsis = node ? node.find('.text-ellipsis') : $('.text-ellipsis'), that = this;
        if (isRemove !== false) {
            that.removeTextEllipsis(node, textEllipsis);
        }
        textEllipsis.each(function () {
            let $this = $(this);
            if ($this[0].clientHeight > 26.5) {
                let td = $this.parent();
                $this.css('width', (td[0].clientWidth - parseInt($('html').css('font-size').replace('px', '')) * 1.7) + 'px').addClass('text-truncate display-block');
                that.createTitle(td, {bodyContent: $this.text()});
            }
        });
        let removePopover = node && node.data('removePopover');
        removePopover && $.each(removePopover, function (i, item) {
            if (!(item instanceof jQuery)) {
                item = $(item);
            }
            setTimeout(function () {
                that.hidePopover(item, true, true)
            }, 25)
        });
    }

    removeTextEllipsis(node, textEllipsisNode) {
        let delay = textEllipsisNode === undefined, removePopover = [], that = this;
        textEllipsisNode = textEllipsisNode || (node ? node.find('.text-ellipsis') : $('.text-ellipsis'));
        textEllipsisNode.each(function () {
            if (!delay) {
                that.removeTitle($(this).removeClass('text-truncate display-block').removeAttr('style').parent())
            } else {
                let popover = that.getPopover($(this).parent());
                popover && removePopover.push(popover);
            }
        });
        removePopover.length > 0 && node && node.data('removePopover', removePopover);
    }

    formPost(url, params) {
        let form = document.createElement("form");
        form.action = url;
        form.method = "post";
        form.style.display = "none";
        for (let x in params) {
            if (params.hasOwnProperty(x)) {
                let opt = document.createElement("textarea");
                opt.name = x;
                opt.value = params[x];
                form.appendChild(opt);
            }
        }
        document.body.appendChild(form);
        form.submit();
        return form;
    }

    ajaxPost(options) {
        $.ajax({
            type: "POST",
            url: this.contentPath + options.url,
            data: options.data,
            dataType: "json",
            success: options.success,
            error: options.error
        });
    }

    axiosPost(options) {
        axios.post(this.contentPath + options.url, !!options.data ? Qs.stringify(options.data) : '', !!this.loginStars ? this.loginStars.getAxiosPostHeader() : {})
            .then((response) => {
                let dataMsg = response.data;
                if (dataMsg.status == 'loginFail') {
                    this.newErrorModal({
                        content: 'alert.' + dataMsg.msgCode,
                        hideFun: () => !!this.loginStars && this.loginStars.toLogin()
                    });
                } else if (dataMsg.status == 'fail') {
                    this.showErrorNoty({
                        timeout: 3000,
                        translateFor: 'message.' + dataMsg.msgCode
                    });
                } else {
                    if (options.successNoty == true) {
                        this.showSuccessNoty({
                            translateFor: 'message.' + (options.successMsgCode || dataMsg.msgCode)
                        });
                    }
                    options.success && options.success(dataMsg.data);
                }
            })
            .catch(function (error) {
                options.error && options.error(error);
            });
    }

    setAttribute(name, value) {
        if (!window.localStorage) {
            let exp = new Date();
            exp.setTime(exp.getTime() + this.getsec("1h") * 1);
            document.cookie = name + "=" + value + ";expires=" + exp.toGMTString();
        } else {
            window.localStorage.setItem(name, value);
        }
    }

    getAttribute(name) {
        if (!window.localStorage) {
            let arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
            if (arr = document.cookie.match(reg)) {
                return arr[2];
            }
        } else {
            return window.localStorage.getItem(name);
        }
        return null;
    }

    removeAttribute(name) {
        if (!window.localStorage) {
            this.setAttribute(name, null);
        } else {
            window.localStorage.removeItem(name);
        }
    }

    getsec(str) {
        let str1 = parseFloat(str.substring(0, str.length - 1));
        let str2 = str.substring(str.length - 1);
        if (str2 == "s") {
            return str1 * 1000;
        } else if (str2 == "m") {
            return str1 * 60 * 1000;
        } else if (str2 == "h") {
            return str1 * 60 * 60 * 1000;
        } else if (str2 == "d") {
            return str1 * 24 * 60 * 60 * 1000;
        }
    }

    load(node, options, loadedFun) {
        let loadExecuteJs = (executeJs) => {
            if (executeJs) {
                if ($.isArray(executeJs)) {
                    getScript(executeJs, 0);
                } else {
                    $.getScript(this.contentPath + executeJs, function () {
                        loadedFun && loadedFun()
                    });
                }
            } else {
                loadedFun && loadedFun();
            }
        };
        let getScript = (executeJs, i) => {
            $.getScript(this.contentPath + executeJs[i], function () {
                i + 1 < executeJs.length ? getScript(executeJs, i + 1) : (loadedFun && loadedFun());
            });
        };
        if (options.url) {
            node.load(this.contentPath + options.url, function () {
                loadExecuteJs(options.executeJs);
            });
        } else {
            loadExecuteJs(options.executeJs);
        }
    }

    contentLoad(name, isNewContent, data) {
        let parentMenuItem = this.getParentMenuItem(name);
        let content = $("#content");
        if (parentMenuItem != null) {
            if (isNewContent) {
                $('li#' + this.page.pageId).removeClass("active");
                $('li#' + name).addClass("active");
                if (content.length > 0) {
                    this.clearAllTimeoutAndInterval(true);
                    this.saveScrollParam(content);
                    content.data('page', this.page);
                    this.pageHolder[pageIndex++] = content.detach();
                }
                this.page = {};
                this.page.pageId = name;
                this.checkTabBar();
                data && this.pushPageContext('data', data);
                content = $('<div class="row" id="content"></div>');
                layout !== 'left' && content.addClass('container m-auto');
                $('#containerFluid').append(content);
                load(content, this.getMenuItem(parentMenuItem, name), () => {
                    this.page.pageNameArray = this.getMenuNameArray(parentMenuItem, name);
                    this.showTabBarPageName();
                    this.translate(content);
                    this.resizeContentWithNiceScroll();
                    this.createContentNiceScroll();
                });
            } else {
                if (content.length > 0) {
                    this.clearAllTimeoutAndInterval(false);
                    load(content, this.getMenuItem(parentMenuItem, name), () => {
                        this.translate(content);
                        this.initNiceScroll(content);
                        this.resizeContentWithNiceScroll();
                        this.createContentNiceScroll();
                    });
                }
            }
        }
    }

    clearAllTimeoutAndInterval(keepTimeoutParam) {
        this.clearPageTimeout(null, keepTimeoutParam);
        eachModalIds((modalId) => this.clearModalTimeout(modalId, null, keepTimeoutParam));
    }

    saveScrollParam(content) {
        let pageNiceScroll = content.getNiceScroll(0);
        this.page['pageScrollX'] = pageNiceScroll.getScrollLeft();
        this.page['pageScrollY'] = pageNiceScroll.getScrollTop();
    }

    loadScrollParam() {
        $('.modal-normal').each(function () {
            let niceScroll = $(this).find('.modal-body').getNiceScroll(0);
            niceScroll.newscrollx && niceScroll.newscrollx !== 0 && niceScroll.setScrollLeft(niceScroll.newscrollx);
            niceScroll.newscrolly && niceScroll.newscrolly !== 0 && niceScroll.setScrollTop(niceScroll.newscrolly);
        });
        this.resizeModalWithNiceScroll();
        let pageScrollX = this.page['pageScrollX'];
        let pageScrollY = this.page['pageScrollY'];
        let pageNiceScroll = $('#content').getNiceScroll(0);
        pageScrollX && pageScrollX !== 0 && pageNiceScroll.setScrollLeft(pageScrollX);
        pageScrollY && pageScrollY !== 0 && pageNiceScroll.setScrollTop(pageScrollY);
    }

    resizeModalWithNiceScroll(isDelay) {
        isDelay !== false ? setTimeout(() => this.resizeModal(), 300) : this.resizeModal();
    }

    resizeModal() {
        $('.modal-normal').each(function () {
            let modalContent = $(this).find('.modal-content');
            !modalContent.data('height') && modalContent.height(($(window).height() - $('.header').height() - $('#tabBar').height()) * 0.8 + "px");
            modalContent.find('.modal-body').getNiceScroll(0).resize();
        });
    }

    showTabBarPageName() {
        let tabBarHeader = $('<div></div>');
        let pageNameArray = this.page.pageNameArray;
        for (let i = 0, length = pageNameArray.length; i < length; i++) {
            tabBarHeader.prepend($('<span class="translate" translateFor="menu.' + pageNameArray[i] + '"></span>'));
            i != length - 1 && tabBarHeader.prepend($('<i class="ion ion-arrow-right-b opacity-6 ml-r-3 mr-r-3"></i>'));
        }
        this.translate($('#tabBarHeader').html(tabBarHeader));
    }

    redirect(name, data) {
        if (name !== this.page.pageId) {
            this.destroyOldContent();
            this.contentLoad(name, true, data);
        }
    }

    contentRefresh() {
        this.destroyOldContent();
        this.contentLoad(this.page.pageId, false);
    }

    destroyOldContent() {
        let that = this;
        $('.popover').each(function () {
            that.hidePopover($(this), true, true)
        });
        $('.daterangepicker').each(function () {
            $(this).remove()
        });
        eachModalIds(function (modalId) {
            that.pushModalContext(modalId, 'checkedRows', [])
        });
        that.pushPageContext('checkedRows', [])
    }

    pageHistory(number) {
        if (this.pageHolder.hasOwnProperty(this.pageIndex + number)) {
            let content = $("#content");
            this.clearAllTimeoutAndInterval(true);
            this.saveScrollParam(content);
            content.data('page', this.page);
            this.pageHolder[pageIndex] = content.detach();
            pageIndex += number;
            this.checkTabBar();
            $('li#' + this.page.pageId).removeClass("active");
            this.page = this.pageHolder[pageIndex].data('page');
            $('#containerFluid').append(this.pageHolder[pageIndex]);
            content = $("#content");
            layout === 'left' ? content.removeClass('container m-auto') : content.addClass('container m-auto');
            this.showTabBarPageName();
            $('li#' + this.page.pageId).addClass("active");
            this.resizeContentWithNiceScroll();
            this.createContentNiceScroll();
            this.loadScrollParam();
            this.loadTimeout();
        }
    }

    createContentNiceScroll() {
        var that = this;
        $('#content').scroll(function () {
            that.showGoDown();
            that.showGoTop();
            that.adjustPosition();
            $('.daterangepicker').each(function () {
                let $this = $(this);
                let daterangepicker = $this.data('daterangepicker');
                if (daterangepicker.isShowing) {
                    daterangepicker.move();
                    let daterangepickerTop = $this.offset().top;
                    daterangepickerTop != 0 && (daterangepickerTop <= $("#content").offset().top || daterangepickerTop >= $(window).height()) && daterangepicker.element.blur() && daterangepicker.hide();
                }
            });
        }).niceScroll({
            railpadding: {
                top: 0,
                right: 0,
                left: 0,
                bottom: 0
            },
            scrollspeed: 60,
            zindex: 1,
            cursorborderradius: "0.5rem",
            cursorwidth: "0.5rem",
            cursorcolor: "rgba(52, 40, 104, 0.2)",
            cursorborder: "rgba(52, 40, 104, 0.2)"
        });
    }

    initNiceScroll(node) {
        let niceScroll = node.getNiceScroll(0);
        if (niceScroll) {
            niceScroll.setScrollLeft(0);
            niceScroll.setScrollTop(0);
        }
    }

    loadTimeout() {
        let pageTimeoutCode = this.getPageContext('pageTimeoutCode');
        let pageTimeoutDelay = this.getPageContext('pageTimeoutDelay');
        pageTimeoutCode && pageTimeoutDelay && this.setPageTimeout(pageTimeoutCode, pageTimeoutDelay);
        eachModalIds((modalId) => {
            let modalTimeoutCode = this.getModalContext(modalId, 'modalTimeoutCode');
            let modalTimeoutDelay = this.getModalContext(modalId, 'modalTimeoutDelay');
            modalTimeoutCode && modalTimeoutDelay && this.setModalTimeout(modalId, modalTimeoutCode, modalTimeoutDelay);
        });
    }

    checkTabBar() {
        let tabBarBack = $('#tabBarBack');
        let tabBarForward = $('#tabBarForward');
        if (this.pageHolder.hasOwnProperty(pageIndex - 1)) {
            tabBarBack.removeClass('disabled');
        } else {
            tabBarBack.addClass('disabled');
        }
        if (this.pageHolder.hasOwnProperty(pageIndex + 1)) {
            tabBarForward.removeClass('disabled');
        } else {
            tabBarForward.addClass('disabled');
        }
    }

    resizeContentWithNiceScroll(cancelShowGoDown) {
        $("#content").css('height', $(window).height() - 119).getNiceScroll().resize();
        cancelShowGoDown != true && this.showGoDown() && this.showGoTop();
    }

    showGoDown() {
        let content = $("#content");
        if (content.length > 0) {
            let scrollTop = content.scrollTop();
            let goDown = $('.go-down');
            content[0].scrollHeight - $(window).height() - scrollTop > 210 ? goDown.fadeIn(100) : goDown.fadeOut(200);
        }
        return true;
    }

    showGoTop() {
        let content = $("#content");
        if (content.length > 0) {
            let goTop = $('.go-top');
            content.scrollTop() > 360 ? goTop.fadeIn(100) : goTop.fadeOut(200);
        }
        return true;
    }

    getEvenNumber(number) {
        number = parseInt(number);
        return number % 2 == 0 ? number : number + 1;
    }


    setCycleValueWithPoint(node, prefix) {
        let times = 1;
        node.data('sourceValue', node.val()).data('cycleWithType', 'value').val(prefix + this.getPoint(times++));
        node.data('cycleInterval', setInterval(function () {
            node.val(prefix + this.getPoint(times++));
        }, 1000));
    }

    setCycleTextWithPoint(node, prefix) {
        let times = 1;
        node.data('sourceValue', node.val()).data('cycleWithType', 'text').text(prefix + this.getPoint(times++));
        node.data('cycleInterval', setInterval(() => node.text(prefix + this.getPoint(times++)), 1000));
    }

    removeCycle(node, value) {
        let type = node.data('cycleWithType');
        if (type === 'value') {
            node.val(node.data('sourceValue'));
        } else if (type === 'text') {
            node.text(node.data('sourceValue'));
        }
        clearInterval(node.data('cycleWithPoint'));
    }

    getPoint(times) {
        let str = ".";
        for (let i = 0; i < times % 6; i++) {
            str += ".";
        }
        return str;
    }

    showErrorNoty(options) {
        options['type'] = 'error';
        options['layout'] = 'center';
        options['animation'] = {open: 'animated fadeInDown', close: 'animated fadeOutUp'};
        this.newNoty(options);
    }

    showSuccessNoty(options) {
        this.newNoty(options);
    }

    newNoty(options) {
        let notyOptions = {
            id: options.id || this.generateID('noty'),
            type: options.type || 'success',
            layout: options.layout || 'bottomRight',
            progressBar: options.progressBar || true,
            timeout: options.timeout || 2500,
            closeWith: options.closeWith || ['click', 'button'],
            animation: options.animation || {open: 'animated bounceInRight', close: 'animated bounceOutRight'}
        };
        if (options.translateFor && options.translateFor !== '') {
            notyOptions['text'] = '<span class="translate" translateFor="' + options.translateFor + '" translateReplace="' + this.getTranslateReplace(options.translateReplace) + '" ></span>';
        } else if (options.text) {
            notyOptions['text'] = '<span>' + options.text + '</span>';
        }
        new Noty(notyOptions, this).show();
    }

    loadInputEmbedCloseBtns(node) {
        node = node ? node.find('input[type="text"]') : $('input[type="text"]');
        let that = this;
        node.each(function () {
            let input = $(this);
            if (input.hasClass('datepicker')) {
                input.after($('<button type="button" class="btn btn-secondary input-embed-right-btn"><i class="la la-calendar"></i></button>').on('click', function () {
                    input.focus()
                }));
            } else if (input.hasClass('doublebox')) {
                input.after($('<button type="button" class="btn btn-transparent input-embed-right-btn input-embed-close-btn"><i class="ion ion-close-circled"></i></button>').on('click', function () {
                    $(this).removeClass('enable').prev().removeClass('pr-r-9').val('');
                    input.data('value', '').data('doubleBox') && input.data('doubleBox').elements.removeAllButton.click();
                    that.removeTitle(input);
                }))
            } else if (!input.hasClass('input-readonly')) {
                input.after($('<button type="button" class="btn btn-transparent input-embed-right-btn input-embed-close-btn"><i class="ion ion-close-circled"></i></button>').on('click', function () {
                    $(this).removeClass('enable').prev().removeClass('pr-r-9').val('')
                })).on("keyup paste focus", function () {
                    input.val() != '' ? input.addClass('pr-r-9').next().addClass('enable') : input.removeClass('pr-r-9').next().removeClass('enable')
                });
            }
        });
    }

    listenDoubleboxWithCloseBtn(input) {
        input.val() != '' ? input.addClass('pr-r-9').next().addClass('enable') : input.removeClass('pr-r-9').next().removeClass('enable')
    }

    hideInputEmbedCloseBtns(node) {
        node = node ? node.find('input[type="text"]') : $('input[type="text"]');
        node.each(function () {
            let input = $(this);
            if (!input.hasClass('datepicker') && !input.hasClass('input-readonly')) {
                input.removeClass('pr-r-9').next().removeClass('enable')
            }
        });
    }

    loadScript(src, callback) {
        let script = document.createElement('script');
        let head = document.getElementsByTagName('head')[0];
        script.type = 'text/javascript';
        script.charset = 'UTF-8';
        script.src = src;
        if (script.addEventListener) {
            script.addEventListener('load', () => callback(), false);
        } else if (script.attachEvent) {
            script.attachEvent('onreadystatechange', () => window.event.srcElement.readyState == 'loaded' && callback());
        }
        head.appendChild(script);
    }
}

Array.prototype.indexOf = function (val) {
    for (let i = 0; i < this.length; i++) {
        if (this[i] == val) return i;
    }
    return -1;
};
Array.prototype.pushWhenNotExist = function (val) {
    !this.includes(val) && this.push(val);
};
Array.prototype.remove = function (val) {
    let index = this.indexOf(val);
    if (index > -1) {
        this.splice(index, 1);
    }
};